diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py
index f541ec0a9..0a33a534d 100644
--- a/sphinx/pycode/ast.py
+++ b/sphinx/pycode/ast.py
@@ -214,7 +214,11 @@ class _UnparseVisitor(ast.NodeVisitor):
 
     def visit_Tuple(self, node: ast.Tuple) -> str:
         if node.elts:
-            return "(" + ", ".join(self.visit(e) for e in node.elts) + ")"
+            elements = ", ".join(self.visit(e) for e in node.elts)
+            # Add a trailing comma if there is only one element in the tuple
+            if len(node.elts) == 1:
+                elements += ","
+            return f"({elements})"
         else:
             return "()"
 
diff --git a/tests/test_pycode_ast.py b/tests/test_pycode_ast.py
index e80062351..b02ae0a37 100644
--- a/tests/test_pycode_ast.py
+++ b/tests/test_pycode_ast.py
@@ -53,8 +53,9 @@ from sphinx.pycode import ast
     ("+ a", "+ a"),                             # UAdd
     ("- 1", "- 1"),                             # UnaryOp
     ("- a", "- a"),                             # USub
-    ("(1, 2, 3)", "(1, 2, 3)"),                   # Tuple
+    ("(1, 2, 3)", "(1, 2, 3)"),                 # Tuple
     ("()", "()"),                               # Tuple (empty)
+    ("(1,)", "(1,)"),                           # Tuple (single element)
 ])
 def test_unparse(source, expected):
     module = ast.parse(source)
diff --git a/tox.ini b/tox.ini
index a363e187f..3b8bc12d0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -27,7 +27,7 @@ setenv =
     PYTHONWARNINGS = all,ignore::ImportWarning:importlib._bootstrap_external,ignore::DeprecationWarning:site,ignore::DeprecationWarning:distutils,ignore::DeprecationWarning:pip._vendor.packaging.version
     PYTEST_ADDOPTS = {env:PYTEST_ADDOPTS:} --color yes
 commands=
-    python -X dev -m pytest --durations 25 {posargs}
+    python -X dev -m pytest -rA --durations 25 {posargs}
 
 [testenv:flake8]
 basepython = python3
